package com.lagou.gateway.filter.factory.verification;

import com.auth0.jwt.interfaces.DecodedJWT;
import com.lagou.gateway.constants.GatewayKnownHeader;
import com.lagou.gateway.filter.factory.AbstractVerificationFilterFactory;
import com.lagou.gateway.util.JWTUtil;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpCookie;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;

import java.util.List;
import java.util.Optional;
import java.util.function.Predicate;

public class JWTVerificationGatewayFilterFactory
        extends AbstractVerificationFilterFactory<JWTVerificationGatewayFilterFactory.Config> {

    private static Logger LOGGER = LoggerFactory.getLogger(JWTVerificationGatewayFilterFactory.class);

    private final PathMatcher pathMatcher = new AntPathMatcher();

    public JWTVerificationGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public Predicate<ServerHttpRequest> requestPredicate(Config config) {
        return (request -> {
            Boolean result = false;
            String requestUri = request.getURI().getPath();
            if (config.getIgnorePaths() != null) {
                for (String ignorePath
                        : config.getIgnorePaths()) {
                    if (this.pathMatcher.match(ignorePath, requestUri)) {
                        result = true;
                        break;
                    }
                }
            }
            if (!result) {
                //从header获取(支持浏览器和app)
                String token = request.getHeaders().getFirst(GatewayKnownHeader.USER_JWT_TOKEN);
                if (StringUtils.isBlank(token)){
                    //从cookie获取(仅支持浏览器)
                    HttpCookie cookie = request.getCookies().getFirst(GatewayKnownHeader.USER_JWT_TOKEN);
                    if (null != cookie)
                        token = cookie.getValue();
                }
                LOGGER.info("token is {}",token);
                Optional<String> optional = Optional.ofNullable(token);
                if (optional.isPresent()) {
                    Optional<DecodedJWT> jwtOptional = Optional.ofNullable(JWTUtil.verify(optional.get(), config.getIssuer(), config.getSecretKey()));
                    result = jwtOptional.isPresent();
                    LOGGER.info("token verification result is {}",result);
                    //set build function
                    jwtOptional.ifPresent(c ->
                            super.setBuildRequest(r ->
                                    r.mutate()
                                            .headers(headers -> headers.remove(GatewayKnownHeader.USER_JWT_TOKEN))
                                            .header(GatewayKnownHeader.GATEWAY_USER_JWT_ID, c.getSubject()).build()
                            )
                    );
                }
            }
            return result;
        });
    }

    public static class Config {
        private List<String> ignorePaths;

        private String secretKey;

        private String issuer;

        public List<String> getIgnorePaths() {
            return ignorePaths;
        }

        public void setIgnorePaths(List<String> ignorePaths) {
            this.ignorePaths = ignorePaths;
        }

        public String getSecretKey() {
            return secretKey;
        }

        public void setSecretKey(String secretKey) {
            this.secretKey = secretKey;
        }

        public String getIssuer() {
            return issuer;
        }

        public void setIssuer(String issuer) {
            this.issuer = issuer;
        }
    }
}
